package service

import (
	"a-common/constant"
	dom "a-common/domain"
	"a-common/myerr"
	"a-common/utils"
	"a-common/utils/excel"
	"a-system/dao"
	"a-system/domain/entity"
	"errors"
	"strconv"
	"strings"
	"sync"

	"github.com/gofiber/fiber/v2"
	"github.com/xuri/excelize/v2"
)

var (
	roleServiceTemp *RoleService
	sysRoleDao      = dao.NewSysRoleDao()
	roleServiceOnce sync.Once
)

type RoleService struct{}

func NewSysRoleService() *RoleService {
	roleServiceOnce.Do(func() {
		roleServiceTemp = &RoleService{}
	})
	return roleServiceTemp
}

// List 分页
func (m *RoleService) List(args *entity.SysRoleDto) (dom.PageVo, error) {
	return sysRoleDao.List(args, false)
}

// Get 查
func (m *RoleService) Get(id string) (entity.SysRolePageVo, error) {
	return sysRoleDao.Get(id)
}

// Add 增
func (m *RoleService) Add(args *entity.SysRoleDto) error {
	// 校验角色名称
	hasName, err := sysRoleDao.CheckRoleNameUnique(args.RoleName, args.RoleId)
	if err != nil {
		return err
	}
	if hasName {
		return errors.New("已存在角色")
	}
	// 校验角色权限标识
	hasKey, err := sysRoleDao.CheckRoleKeyUnique(args.RoleName, args.RoleId)
	if err != nil {
		return err
	}
	if hasKey {
		return errors.New("已存在权限标识")
	}
	return sysRoleDao.Add(args)
}

// Edit 改
func (m *RoleService) Edit(args *entity.SysRoleDto) error {
	// 校验角色名称
	hasName, err := sysRoleDao.CheckRoleNameUnique(args.RoleName, args.RoleId)
	if err != nil {
		return err
	}
	if hasName {
		return errors.New("已存在角色名称")
	}
	// 校验角色权限标识
	hasKey, err := sysRoleDao.CheckRoleKeyUnique(args.RoleName, args.RoleId)
	if err != nil {
		return err
	}
	if hasKey {
		return errors.New("已存在角色权限标识")
	}

	// 更新角色信息
	return sysRoleDao.Edit(args)
}

// Del 删
func (m *RoleService) Del(ids string) error {
	return sysRoleDao.Del(ids)
}

// Export 导出
func (m *RoleService) Export(args *entity.SysRoleDto) (*excelize.File, error) {
	var pageVo dom.PageVo
	pageVo, err := sysRoleDao.List(args, true)
	if err != nil {
		return nil, err
	}
	return excel.NormalDynamicExport(pageVo.Rows, "Sheet1", "角色表", "", true, false, map[string]string{})
}

// ChangeStatus 切换状态
func (m *RoleService) ChangeStatus(args *entity.SysRoleDto) (int64, error) {
	return sysRoleDao.ChangeStatus(strconv.FormatInt(args.RoleId, 10), args.Status)
}

// DataScope 修改保存数据权限
func (m *RoleService) DataScope(args *entity.SysRoleDto, uid int64) error {
	// 校验角色是否有数据权限
	if uid != constant.ADMIN_ID {
		v, err := sysRoleDao.Get(strconv.FormatInt(args.RoleId, 10))
		if v.RoleId == 0 || err != nil {
			return err
		}
	}
	return sysRoleDao.AuthDataScope(args)
}

// DeptTree 部门树
func (m *RoleService) DeptTree(id string) (fiber.Map, error) {
	// 获取选中项
	roleVo, err := sysRoleDao.Get(id)
	if err != nil {
		return nil, err
	}
	checkedKeys, err := sysDeptDao.GetDeptIdsByRoleId(roleVo.RoleId, roleVo.DeptCheckStrictly)
	if err != nil {
		return nil, err
	}

	// 构建部门树
	vPage, err := sysDeptDao.List(&entity.SysDeptDto{})
	if err != nil {
		return nil, err
	}
	rows, _ := vPage.Rows.([]entity.SysDeptPageVo)

	var nodeList []*utils.TreeNode
	for _, item := range rows {
		nodeList = append(nodeList, &utils.TreeNode{
			ID:       int(item.DeptId),
			Label:    item.DeptName,
			ParentId: int(item.ParentId),
			Weight:   item.OrderNum,
		})
	}
	return fiber.Map{
		"checkedKeys": checkedKeys,
		"depts":       utils.NewTreeUtils().GetTreeRecursive(nodeList, 0),
	}, nil
}

// EditAndMenu
func (m *RoleService) EditAndMenu(args *entity.SysRoleDto) error {
	return sysRoleDao.Edit(args)
}

func (m *RoleService) EditAndDept(args *entity.SysRoleDto) error {
	err := sysRoleDao.Edit(args)
	if err != nil {
		return err
	}
	// 更新角色权限部门
	return sysRoleDao.UpdateRoleDept(args.RoleId, args.DeptIds)
}

// AllocatedList 查询已分配用户角色列表
func (m *RoleService) AllocatedList(args *entity.UserDto) (dom.PageVo, error) {
	return sysUserDao.GetAllocatedList(args)
}

// UnallocatedList 根据条件分页查询未分配用户角色列表
func (m *RoleService) UnallocatedList(args *entity.UserDto) (vPage dom.PageVo, err error) {
	userIds, err := sysUserDao.GetUserIdsByRoleId(args.RoleId)
	if err != nil {
		return vPage, err
	}
	return sysUserDao.GetUnallocatedList(args, userIds)
}

// SelectAll 批量选择用户授权
func (m *RoleService) SelectAll(roleId, userIds string, uid int64) error {
	// 校验角色是否有数据权限
	if uid != constant.ADMIN_ID {
		v, err := sysRoleDao.Get(roleId)
		if v.RoleId == 0 || err != nil {
			return myerr.ERR_SYS_403
		}
	}
	rId, err := strconv.ParseInt(roleId, 10, 64)
	if err != nil {
		return err
	}
	stringSlice := strings.Split(userIds, `,`)
	var uIds []int64
	for _, str := range stringSlice {
		num, err := strconv.ParseInt(str, 10, 64)
		if err != nil {
			return err
		}
		uIds = append(uIds, num)
	}
	return sysRoleDao.InsertAuthUsers(rId, uIds)
}

// Cancel 取消授权用户
func (m *RoleService) Cancel(args *entity.SysUserRole) (int64, error) {
	return sysRoleDao.DeleteAuthUser(args.RoleId, args.UserId)
}

// CancelAll 批量取消授权用户
func (m *RoleService) CancelAll(roleId, userIds string) (int64, error) {
	rId, err := strconv.ParseInt(roleId, 10, 64)
	if err != nil {
		return 0, err
	}

	stringSlice := strings.Split(userIds, `,`)
	var uIds []int64
	for _, str := range stringSlice {
		num, err := strconv.ParseInt(str, 10, 64)
		if err != nil {
			return 0, err
		}
		uIds = append(uIds, num)
	}
	return sysRoleDao.DeleteAuthUsers(rId, uIds)
}
